package com.yu.demo.user.application.service;

import com.yu.demo.user.application.converter.UserConverter;
import com.yu.demo.user.application.dto.CreateUserRequest;
import com.yu.demo.user.application.dto.UpdateUserRequest;
import com.yu.demo.user.application.dto.UserResponse;
import com.yu.demo.user.domain.entity.User;
import com.yu.demo.user.domain.repository.UserRepository;
import com.yu.demo.user.domain.service.UserDomainService;
import com.yu.demo.user.domain.valueobject.UserId;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Optional;

/**
 * 用户应用服务
 * 协调领域对象完成业务用例
 */
@Service
@Transactional
public class UserApplicationService {
    
    private final UserRepository userRepository;
    private final UserDomainService userDomainService;
    private final UserConverter userConverter;
    
    public UserApplicationService(UserRepository userRepository, 
                                UserDomainService userDomainService,
                                UserConverter userConverter) {
        this.userRepository = userRepository;
        this.userDomainService = userDomainService;
        this.userConverter = userConverter;
    }
    
    /**
     * 创建用户
     */
    public UserResponse createUser(CreateUserRequest request) {
        User user = userConverter.toDomain(request);
        
        // 验证用户是否可以注册
        if (!userDomainService.canRegister(user)) {
            throw new IllegalArgumentException("用户名或邮箱已存在");
        }
        
        User savedUser = userRepository.save(user);
        return userConverter.toResponse(savedUser);
    }
    
    /**
     * 根据ID获取用户
     */
    @Transactional(readOnly = true)
    public Optional<UserResponse> getUserById(Integer id) {
        return userRepository.findById(new UserId(id))
                .map(userConverter::toResponse);
    }
    
    /**
     * 根据用户名获取用户
     */
    @Transactional(readOnly = true)
    public Optional<UserResponse> getUserByUsername(String username) {
        return userRepository.findByUsername(new com.yu.demo.user.domain.valueobject.Username(username))
                .map(userConverter::toResponse);
    }
    
    /**
     * 获取所有用户
     */
    @Transactional(readOnly = true)
    public List<UserResponse> getAllUsers() {
        List<User> users = userRepository.findAll();
        return userConverter.toResponseList(users);
    }
    
    /**
     * 获取所有激活的用户
     */
    @Transactional(readOnly = true)
    public List<UserResponse> getAllActiveUsers() {
        List<User> users = userRepository.findAllActive();
        return userConverter.toResponseList(users);
    }
    
    /**
     * 更新用户信息
     */
    public UserResponse updateUser(Integer id, UpdateUserRequest request) {
        User user = userRepository.findById(new UserId(id))
                .orElseThrow(() -> new IllegalArgumentException("用户不存在"));
        
        // 验证是否可以更新
        if (!userDomainService.canUpdateProfile(user, 
                request.getUsername() != null ? new com.yu.demo.user.domain.valueobject.Username(request.getUsername()) : null,
                request.getEmail() != null ? new com.yu.demo.user.domain.valueobject.Email(request.getEmail()) : null)) {
            throw new IllegalArgumentException("用户名或邮箱已存在");
        }
        
        userConverter.updateDomain(user, request);
        User updatedUser = userRepository.save(user);
        return userConverter.toResponse(updatedUser);
    }
    
    /**
     * 删除用户
     */
    public void deleteUser(Integer id) {
        UserId userId = new UserId(id);
        if (!userRepository.findById(userId).isPresent()) {
            throw new IllegalArgumentException("用户不存在");
        }
        userRepository.delete(userId);
    }
    
    /**
     * 激活用户
     */
    public UserResponse activateUser(Integer id) {
        User user = userRepository.findById(new UserId(id))
                .orElseThrow(() -> new IllegalArgumentException("用户不存在"));
        
        user.activate();
        User updatedUser = userRepository.save(user);
        return userConverter.toResponse(updatedUser);
    }
    
    /**
     * 停用用户
     */
    public UserResponse deactivateUser(Integer id) {
        User user = userRepository.findById(new UserId(id))
                .orElseThrow(() -> new IllegalArgumentException("用户不存在"));
        
        user.deactivate();
        User updatedUser = userRepository.save(user);
        return userConverter.toResponse(updatedUser);
    }
    
    /**
     * 更改用户角色
     */
    public UserResponse changeUserRole(Integer currentUserId, Integer targetUserId, String newRole) {
        User currentUser = userRepository.findById(new UserId(currentUserId))
                .orElseThrow(() -> new IllegalArgumentException("当前用户不存在"));
        
        User targetUser = userRepository.findById(new UserId(targetUserId))
                .orElseThrow(() -> new IllegalArgumentException("目标用户不存在"));
        
        // 验证是否可以更改角色
        if (!userDomainService.canChangeRole(currentUser, targetUser, newRole)) {
            throw new IllegalArgumentException("无权限更改用户角色");
        }
        
        targetUser.changeRole(new com.yu.demo.user.domain.valueobject.UserRole(newRole));
        User updatedUser = userRepository.save(targetUser);
        return userConverter.toResponse(updatedUser);
    }
    
    /**
     * 记录用户登录
     */
    public void recordUserLogin(Integer id) {
        User user = userRepository.findById(new UserId(id))
                .orElseThrow(() -> new IllegalArgumentException("用户不存在"));
        
        user.recordLogin();
        userRepository.save(user);
    }
    
    /**
     * 获取用户统计信息
     */
    @Transactional(readOnly = true)
    public UserStatistics getUserStatistics() {
        long totalCount = userRepository.count();
        long activeCount = userRepository.countActive();
        return new UserStatistics(totalCount, activeCount);
    }
    
    /**
     * 用户统计信息内部类
     */
    public static class UserStatistics {
        private final long totalCount;
        private final long activeCount;
        
        public UserStatistics(long totalCount, long activeCount) {
            this.totalCount = totalCount;
            this.activeCount = activeCount;
        }
        
        public long getTotalCount() { return totalCount; }
        public long getActiveCount() { return activeCount; }
    }
}
